package com.tsing.cli.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.useragent.UserAgent;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tsing.cli.common.annotation.Logger;
import com.tsing.cli.common.vo.PageResultVO;
import com.tsing.cli.system.entity.LogEntity;
import com.tsing.cli.system.mapper.LogMapper;
import com.tsing.cli.system.service.ILogService;
import com.tsing.cli.system.vo.req.LogPageReqVO;
import com.tsing.cli.system.vo.resp.LogPageRespVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import net.dreamlu.mica.ip2region.core.Ip2regionSearcher;
import net.dreamlu.mica.ip2region.core.IpInfo;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 操作日志表 服务实现类
 * </p>
 *
 * @author TheTsing
 */
@Service
@RequiredArgsConstructor
public class LogServiceImpl extends ServiceImpl<LogMapper, LogEntity> implements ILogService {

    private final Ip2regionSearcher ip2regionSearcher;

    @Override
    public void save(String username, String ip, UserAgent userAgent, long requestTime, ProceedingJoinPoint joinPoint) {
        baseMapper.insert(build(username, ip, userAgent, requestTime, joinPoint));
    }

    @Override
    public void save(String username, String ip, UserAgent userAgent, long requestTime, JoinPoint joinPoint, Throwable e) {
        LogEntity logEntity = build(username, ip, userAgent, requestTime, joinPoint);
        if (Objects.nonNull(e)) {
            logEntity.setException(JSON.toJSONString(e, new SimplePropertyPreFilter(Throwable.class, "code", "description", "type")));
        }
        baseMapper.insert(logEntity);
    }

    private LogEntity build(String username, String ip, UserAgent userAgent, long requestTime, JoinPoint joinPoint) {
        IpInfo ipInfo = null;
        try {
            ipInfo = ip2regionSearcher.memorySearch(ip);
        } catch (Exception e) {
        }
        List<Object> argList = new ArrayList<>();
        for (Object arg : joinPoint.getArgs()) {
            if (Objects.isNull(arg) || arg instanceof MultipartFile || arg instanceof MultipartFile[] || arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                continue;
            }
            argList.add(arg);
        }
        String params = switch (argList.size()) {
            case 0 -> null;
            case 1 -> JSON.toJSONString(argList.get(0));
            default -> JSON.toJSONString(argList);
        };
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 记录登录用户，隐藏密码信息
        if ("login".equals(signature.getName()) && Objects.nonNull(params)) {
            JSONObject jsonObject = JSON.parseObject(params);
            username = jsonObject.get("username").toString();
            jsonObject.put("password", "***");
            params = jsonObject.toJSONString();
        }
        return new LogEntity()
                .setUsername(username)
                .setIp(ip)
                .setAddress(Objects.isNull(ipInfo) ? "Unknown" : ipInfo.getAddress())
                .setBrowser(Objects.isNull(userAgent) ? "Unknown" : userAgent.getBrowser().toString())
                .setMethod(joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()")
                .setDescription(signature.getMethod().getAnnotation(Logger.class).description())
                .setParams(params)
                .setRequestTime(requestTime);
    }

    @Override
    public void deleteLog(List<String> reqVO) {
        baseMapper.deleteBatchIds(reqVO);
    }

    @Override
    public PageResultVO<LogPageRespVO> logPage(LogPageReqVO reqVO) {
        IPage<LogEntity> page = new Page<>(reqVO.getPageNum(), reqVO.getPageSize());
        lambdaQuery()
                .ge(Objects.nonNull(reqVO.getStartTime()), LogEntity::getCreateTime, reqVO.getStartTime())
                .le(Objects.nonNull(reqVO.getEndTime()), LogEntity::getCreateTime, reqVO.getEndTime())
                .like(Objects.nonNull(reqVO.getUsername()), LogEntity::getUsername, reqVO.getUsername())
                .page(page);
        return new PageResultVO<>(page, BeanUtil.copyToList(page.getRecords(), LogPageRespVO.class));
    }

}
